using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Markup;
using System.Xml;
using System.IO;
using ViewOn.Helper.WPF;
using ViewOnAddInsAPI.Helper.WPF;
using ViewOnAddInsAPI.HostContract;
using ViewOnAddInsAPI.HostContract.Media;

#region Copyright (c) 2006, 2007, 2008 ViewOn Media Services. All rights reserved.

/*
 Copyright (c) 2006, 2007, 2008 ViewOn Media Services. All rights reserved.
 This work is copyrighted in its entirety. Permission to use "ViewOn.tv"
 material may be granted only after we receive a written request from you,
 and you receive written permission from us.

 While ViewOn Media Services provides the information herein to anyone,
 we retain copyright on all code, text, graphic images, and other content.
 This means that you may not distribute the code, the text or graphics to others without the
 express written permission of ViewOn Media Services; "mirror" this information on your server
 without our permission; or modify or reuse the code, text or graphics on our servers.
 You may print copies of the information for your own personal use; and, you may reference
 the Service from your own documents. Any commercial use of this material is prohibited without
 the written permission of ViewOn Media Services. In all copies of this information, you must
 retain this notice and any other copyright notices originally included with such information.

 This material may be protected by U.S. and International Copyright laws, and you are legally
 bound by the copyright notices on those systems.

 "ViewOn" logos and other official symbols or graphics may not be used in connection with any
 product or service that has not been expressly authorized in advance in writing or in any manner
 that is likely to cause confusion among the users of this or other Web sites or among the public.
 All other seals, graphics or trademarks of organizations not affiliated with ViewOn Media Services
 that appear on this site are the property of their respective owners.

 ViewOn Media Services reserve all other rights. 
*/

#endregion

#region ViewOn.tv Source Code Licence

/*
This license governs use of the ViewOn.tv software. If you use the software, you accept this license. If you do not accept the license, do not use the software.

1. Summary

The source code is made available to view for reference purposes or to contribute to the project only. Developers may not distribute or modify the code for commercial or non-commercial purposes without express Agreement of View On Media Services.

2. Definitions

The terms "reproduce," "reproduction," and "distribution" have the same meaning here as under U.S. copyright law.
"Licensor" means the company "ViewOn Media Services".
"You" means the licensee of the software, who is not engaged in designing, developing, or testing other software, that has the same or substantially the same features or functionality as the software.
"Your company" means the company you worked for when you downloaded the software.
"Reference use" means use of the software within your company as a reference, in read only form, for the sole purposes of debugging and maintaining your products. For clarity, "reference use" does NOT include (a) the right to use the software for purposes of designing, developing, or testing other software, that has the same or substantially the same features or functionality as the software, and (b) the right to distribute the software outside of your company.
"Licensed patents" means any Licensor patent claims which read directly on the software as distributed by the Licensor under this license.

3. Grant of Rights

(A) Copyright Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive, worldwide, royalty-free copyright license to reproduce the software for reference use.
(B) Patent Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive, worldwide, royalty-free patent license under licensed patents for reference use.
4. Limitations
(A) No Trademark License- This license does not grant you any rights to use the Licensor's name, logo, or trademarks.
(B) If you begin patent litigation against the Licensor over patents that you think may apply to the software (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically.
(C) The software is licensed "as-is." You bear the risk of using it. The Licensor gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the Licensor excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
 */

#endregion

namespace ViewOnAddInsAPI.Helper.WPF
{
    /// <summary>
    /// Create XAML like this :
    /// 	<Canvas
    ///			x:Name="childWindowsCanvas"
    ///			Background="#00FFFFFF"
    ///         ClipToBounds="True"
    ///			HorizontalAlignment="Stretch"
    ///			VerticalAlignment="Stretch">
    ///			<ContentPresenter x:Name="contentPresenter"/>
    ///		</Canvas>
    /// 
    /// The canvas contains the windows
    /// The content presenter contains childs controls
    /// </summary>
    sealed public class Desktop
    {

        #region Variables

        private string _key;

        //---- Moving
        private Point _startDrag;
        private bool _isMovingWindow = false;
        private bool _isMovingDesktopIcons = false;

        //---- Desktop
        public Canvas ChildWindowsCanvas;
        private ContentPresenter _contentPresenter;

        //---- Freeze the drag & drop of other controls during some operations
        private List<FrameworkElement> _freezedDragDrop;

        //---- Selected window
        private ChildWindowDecorator _selectedChildWindow = null;

        //---- Display
        private double _percentSpace = -1;

        //---- Attach / Detach
        private List<ChildWindowDecorator> _detachedChildren = new List<ChildWindowDecorator>();

        //---- Desktop icons
        private List<DesktopIcon> _selectedDesktopIcons = new List<DesktopIcon>(0);

        //---- Desktop selection
        private bool _supportSelection = false;

        private bool _startSelection = false;
        private System.Windows.Shapes.Path _selectionPath;
        private PolyQuadraticBezierSegment _selectionCurve;

        #endregion

        #region Constructor

        /// <summary>
        /// Create a desktop that will contains and manage 'child windows'.
        /// </summary>
        /// <param name="key">The desktop key.</param>
        /// <param name="childWindowsCanvas">The parent canvas.</param>
        /// <param name="contentPresenter">The content presenter</param>
        public Desktop(string key, Canvas childWindowsCanvas, ContentPresenter contentPresenter)
        {
            _key = key;

            ChildWindowsCanvas = childWindowsCanvas;
            _contentPresenter = contentPresenter;

            // Allow focus management
            ChildWindowsCanvas.Focusable = true;
            //FocusManager.SetIsFocusScope(ChildWindowsCanvas, true);

            ChildWindowsCanvas.SizeChanged += new SizeChangedEventHandler(childWindowsCanvas_SizeChanged);
            ChildWindowsCanvas.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(_childWindowsCanvas_PreviewMouseLeftButtonDown);
            ChildWindowsCanvas.MouseLeftButtonUp += new MouseButtonEventHandler(childWindowsCanvas_PreviewMouseLeftButtonUp);
            ChildWindowsCanvas.MouseMove += new MouseEventHandler(childWindowsCanvas_MouseMove);

            System.Windows.Input.Keyboard.AddKeyDownHandler(Host.ApplicationWindow, new KeyEventHandler(_childWindowsCanvas_KeyDown));

            //---- Add the selection path
            string xaml = "<Path Fill=\"{DynamicResource VOColor02}\" Stroke=\"{DynamicResource VOColor13}\" StrokeThickness=\"2\" Opacity=\"0.3\"";
            xaml += " xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"";
            xaml += " xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">";
            xaml += "<Path.Data>";
            xaml += "<PathGeometry>";
            xaml += "<PathGeometry.Figures>";
            xaml += "<PathFigureCollection>";
            xaml += "<PathFigure StartPoint=\"0,0\">";
            xaml += "<PathFigure.Segments>";
            xaml += "<PolyQuadraticBezierSegment/>";
            xaml += "</PathFigure.Segments>";
            xaml += "</PathFigure>";
            xaml += "</PathFigureCollection>";
            xaml += "</PathGeometry.Figures>";
            xaml += "</PathGeometry>";
            xaml += "</Path.Data>";
            xaml += "</Path>";

            StringReader stringReader = new StringReader(xaml);
            XmlReader xmlReader = XmlTextReader.Create(stringReader, new XmlReaderSettings());
            _selectionPath = (System.Windows.Shapes.Path)XamlReader.Load(xmlReader);
            _selectionCurve = (PolyQuadraticBezierSegment)((PathFigure)((PathGeometry)_selectionPath.Data).Figures[0]).Segments[0];

            ChildWindowsCanvas.Children.Add(_selectionPath);
        }

        #endregion

        #region Properties

        /// <summary>
        /// The desktop key.
        /// </summary>
        public string Key
        {
            get
            {
                return _key;
            }
        }

        /// <summary>
        /// Does the desktop support selection of the icons.
        /// </summary>
        public bool SupportSelection
        {
            get
            {
                return _supportSelection;
            }
            set
            {
                _supportSelection = value;
            }
        }

        /// <summary>
        /// Returns the list of selected desktop icons.
        /// </summary>
        public List<DesktopIcon> SelectedDesktopIcons
        {
            get
            {
                return _selectedDesktopIcons;
            }
        }

        internal bool IsMovingDesktopIcon
        {
            get
            {
                return _isMovingDesktopIcons;
            }
        }

        #endregion

        #region Child Window : Add

        public void AddChildWindow(ChildWindowDecorator decorator, bool isModal)
        {
            FrameworkElement parent = decorator.Parent as FrameworkElement;
            ChildWindowsCanvas.Children.Add(parent);

            if (decorator.StartupPosition == WindowStartupLocation.CenterOwner)
                parent.Loaded += new RoutedEventHandler(childWindow_LoadedCenterOwner);

            if (isModal)
                _contentPresenter.IsEnabled = false;
        }

        void childWindow_LoadedCenterOwner(object sender, RoutedEventArgs e)
        {
            FrameworkElement window = sender as FrameworkElement;

            if (_percentSpace < 0)
            {
                Canvas.SetLeft(window, (ChildWindowsCanvas.ActualWidth - window.ActualWidth) / 2);
                Canvas.SetTop(window, (ChildWindowsCanvas.ActualHeight - window.ActualHeight) / 2);
            }
            else
            {
                int newWidth = (int)(ChildWindowsCanvas.ActualWidth * _percentSpace);
                int newHeight = (int)(ChildWindowsCanvas.ActualHeight * _percentSpace);
                int newX = (int)(ChildWindowsCanvas.ActualWidth * ((1.0 - _percentSpace) / 2));
                int newY = (int)(ChildWindowsCanvas.ActualHeight * ((1.0 - _percentSpace) / 2));

                window.Width = newWidth;
                window.Height = newHeight;
                Canvas.SetLeft(window, newX);
                Canvas.SetTop(window, newY);
            }

            _percentSpace = -1;

            window.Loaded -= new RoutedEventHandler(childWindow_LoadedCenterOwner);
        }

        #endregion

        #region Child Window : Remove

        internal void RemoveChildWindow(ChildWindowDecorator child)
        {
            if (child == _selectedChildWindow)
                _selectedChildWindow = null;

            FrameworkElement parent = (FrameworkElement)child.Parent;
            ChildWindowsCanvas.Children.Remove(parent);

            _contentPresenter.IsEnabled = true;
        }

        #endregion

        #region ChildWindow : Move

        internal void MoveChildWindow(ChildWindowDecorator decorator, Point location)
        {
            FrameworkElement parent = (FrameworkElement)decorator.Parent;
            Canvas.SetLeft(parent, location.X);
            Canvas.SetTop(parent, location.Y);

            //---- Save the new position
            decorator.UpdateXml();
        }

        #endregion

        #region Desktop icons : Add

        public void AddDesktopIcon(DesktopIcon icon)
        {
            icon.UpdateTitle();

            ChildWindowsCanvas.Children.Add(icon);
            BringToTopDesktopIcon(icon);
        }

        #endregion

        #region Desktop icons : Remove

        internal void RemoveDesktopIcon(DesktopIcon icon, bool closeRepresentingControl)
        {
            if (_selectedDesktopIcons.Contains(icon))
                _selectedDesktopIcons.Remove(icon);

            ChildWindowsCanvas.Children.Remove(icon);

            // Close the representing control too
            if (closeRepresentingControl)
                icon.Decorator.Close();
        }

        #endregion

        #region Desktop Icons : Move

        internal void MoveDesktopIcon(DesktopIcon icon, Point location)
        {
            // Move the icon
            Canvas.SetLeft(icon, location.X);
            Canvas.SetTop(icon, location.Y);

            // Save the new position
            icon.Decorator.UpdateXml();
        }

        #endregion

        #region Desktop Icons : Find

        public DesktopIcon FindDesktopIcon(MediaData mediaData)
        {
            foreach (FrameworkElement element in ChildWindowsCanvas.Children)
                if (element is DesktopIcon && ((DesktopIcon)element).Decorator.MediaData == mediaData)
                    return (DesktopIcon)element;

            return null;
        }

        #endregion

        #region OnStartResizingChildWindow / OnEndResizingChildWindow

        public void OnStartResizingChildWindow()
        {
            FreezeDragDrop();
        }

        public void OnEndResizingChildWindow()
        {
            UnfreezeDragDrop();
        }

        #endregion

        #region OnStartMoveChildWindow

        internal void OnStartMoveChildWindow(ChildWindowDecorator child, MouseButtonEventArgs e)
        {
            //---- Put the window on top
            child.BringToTop();

            //---- Freeze the drag & drop
            FreezeDragDrop();

            //---- Start to drag
            _startDrag = e.GetPosition(ChildWindowsCanvas);
            _isMovingWindow = true;

            ClearSelection();
            _selectedChildWindow = child;
        }

        #endregion

        #region OnStartMoveDesktopIcon

        internal void OnStartMoveDesktopIcon(DesktopIcon desktopIcon, MouseButtonEventArgs e)
        {
            if (!_supportSelection)
                return;

            //---- Put the window on top
            BringToTop(desktopIcon);

            //---- Get the focus on the desktop
            FocusManager.SetFocusedElement(ChildWindowsCanvas, ChildWindowsCanvas);

            //---- Start to drag
            _startDrag = e.GetPosition(ChildWindowsCanvas);
            _isMovingDesktopIcons = true;
            FreezeDragDrop();

            //---- Set the new selection
            bool isCtrlKeyPressed = ((System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.LeftCtrl) & KeyStates.Down) > 0) ||
                                    ((System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.RightCtrl) & KeyStates.Down) > 0);
            if (!isCtrlKeyPressed)
                ClearSelection();
            desktopIcon.IsSelected = true;
        }

        #endregion

        #region Child Windows canvas : Events

        void _childWindowsCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount != 1)
                return;

            //---- Start the selection
            if (_supportSelection &&
                _selectedChildWindow == null &&
                !IsMouseOverDekstopElement(e.GetPosition(ChildWindowsCanvas)) &&
                !_isMovingDesktopIcons)
            {
                _startSelection = true;
                _selectionCurve.Points.Clear();
                ((PathFigure)((PathGeometry)_selectionPath.Data).Figures[0]).StartPoint = new Point(e.GetPosition(ChildWindowsCanvas).X, e.GetPosition(ChildWindowsCanvas).Y);

                FreezeDragDrop();

                // Get the focus on the desktop
                FocusManager.SetFocusedElement(ChildWindowsCanvas, ChildWindowsCanvas);
            }

            //---- Unselect the icons
            if (_supportSelection &&
                e.ClickCount == 1 &&
                !IsMouseOverDekstopElement(e.GetPosition(ChildWindowsCanvas)))
                ClearSelection();

            //---- Start moving the icons
            if (_supportSelection &&
                _selectedDesktopIcons.Count > 0 &&
                IsMouseOverSelectedDesktopIcon(e.GetPosition(ChildWindowsCanvas)))
            {
                _isMovingDesktopIcons = true;
                FreezeDragDrop();
                _startDrag = e.GetPosition(ChildWindowsCanvas);
            }
        }

        void childWindowsCanvas_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //---- Save the position
            if (_selectedChildWindow != null)
                _selectedChildWindow.UpdateXml();

            if (_selectedDesktopIcons.Count > 0)
                foreach (DesktopIcon icon in _selectedDesktopIcons)
                    icon.Decorator.UpdateXml();

            //---- Stop moving window
            _isMovingWindow = false;
            _isMovingDesktopIcons = false;
            UnfreezeDragDrop();

            //--- End of selection
            if (_supportSelection && _startSelection)
            {
                _startSelection = false;

                ClearSelection();

                foreach (FrameworkElement element in ChildWindowsCanvas.Children)
                    if (element is DesktopIcon)
                    {
                        DesktopIcon icon = (DesktopIcon)element;

                        Point point = new Point(Canvas.GetLeft(element), Canvas.GetTop(element));

                        if (_selectionPath.RenderedGeometry.FillContains(icon.TopLeft(point)) ||
                        _selectionPath.RenderedGeometry.FillContains(icon.TopRight(point)) ||
                        _selectionPath.RenderedGeometry.FillContains(icon.BottomLeft(point)) ||
                        _selectionPath.RenderedGeometry.FillContains(icon.BottomRight(point)))
                            ((DesktopIcon)element).IsSelected = true;

                        //if (_selectionPath.InputHitTest(icon.TopLeft(point)) != null ||
                        //_selectionPath.InputHitTest(icon.TopRight(point)) != null ||
                        //_selectionPath.InputHitTest(icon.BottomLeft(point)) != null ||
                        //_selectionPath.InputHitTest(icon.BottomRight(point)) != null)
                        //    ((DesktopIcon)element).IsSelected = true;
                    }

                // Set selection
                _selectionCurve.Points.Clear();

                // Get the focus on the desktop
                FocusManager.SetFocusedElement(ChildWindowsCanvas, ChildWindowsCanvas);
            }
        }

        void childWindowsCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            //---- Is moving window
            if (_selectedChildWindow != null && _isMovingWindow)
            {
                Point endDrag = e.GetPosition(ChildWindowsCanvas);

                double x = Canvas.GetLeft((UIElement)_selectedChildWindow.Parent);
                double y = Canvas.GetTop((UIElement)_selectedChildWindow.Parent);

                Canvas.SetLeft((UIElement)_selectedChildWindow.Parent, x + endDrag.X - _startDrag.X);
                Canvas.SetTop((UIElement)_selectedChildWindow.Parent, y + endDrag.Y - _startDrag.Y);

                _startDrag = endDrag;
            }

            //---- Is moving icons
            if (_selectedDesktopIcons.Count > 0 && _isMovingDesktopIcons)
            {
                Point endDrag = e.GetPosition(ChildWindowsCanvas);

                foreach (DesktopIcon icon in _selectedDesktopIcons)
                {
                    double x = Canvas.GetLeft(icon);
                    double y = Canvas.GetTop(icon);

                    Canvas.SetLeft(icon, x + endDrag.X - _startDrag.X);
                    Canvas.SetTop(icon, y + endDrag.Y - _startDrag.Y);
                }

                _startDrag = endDrag;
            }

            //---- Selection
            if (_supportSelection && _startSelection && _selectedDesktopIcons.Count < 1)
            {
                // Add a point
                _selectionCurve.Points.Add(new Point(e.GetPosition(ChildWindowsCanvas).X, e.GetPosition(ChildWindowsCanvas).Y));
                e.Handled = true;
            }
        }

        private void childWindowsCanvas_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
        {
            Canvas.SetLeft(_contentPresenter, 0);
            Canvas.SetTop(_contentPresenter, 0);
            _contentPresenter.Width = e.NewSize.Width;
            _contentPresenter.Height = e.NewSize.Height;
        }

        #endregion

        #region Freeze Drag & Drop

        private void FreezeDragDrop()
        {
            if (_freezedDragDrop != null)
                return;

            XamDataGridDragManager<MediaData>.FreezeAllManagers = true;

            _freezedDragDrop = new List<FrameworkElement>();

            // Not usefull - but use CPU :-P
            //FreezeDragDropLogicalTree(ChildWindowsCanvas);
        }

        private void FreezeDragDropLogicalTree(FrameworkElement current)
        {
            if (current.AllowDrop)
            {
                _freezedDragDrop.Add(current);
                current.AllowDrop = false;
            }

            foreach (object logicalChild in LogicalTreeHelper.GetChildren((FrameworkElement)current))
                if (logicalChild is FrameworkElement)
                    FreezeDragDropLogicalTree((FrameworkElement)logicalChild);
        }

        private void UnfreezeDragDrop()
        {
            if (_freezedDragDrop == null)
                return;

            XamDataGridDragManager<MediaData>.FreezeAllManagers = false;

            foreach (FrameworkElement element in _freezedDragDrop)
                element.AllowDrop = true;

            _freezedDragDrop = null;
        }

        #endregion

        #region Events : Keyboard

        void _childWindowsCanvas_KeyDown(object sender, KeyEventArgs e)
        {
            if (!_supportSelection)
                return;

            //---- Delete the selection
            if (e.Key == System.Windows.Input.Key.Delete)
            {
                Point mousePosition = Mouse.GetPosition(ChildWindowsCanvas);
                if (ChildWindowsCanvas.InputHitTest(mousePosition) != null && !IsMouseOverChildWindow(mousePosition))
                    RemoveSelectedDesktopIcons();
            }
        }

        #endregion

        #region RemoveSelectedDesktopIcons

        public void RemoveSelectedDesktopIcons()
        {
            //---- Delete the selection
            for (int index = _selectedDesktopIcons.Count - 1; index > -1; index--)
                _selectedDesktopIcons[index].Close();
        }

        #endregion

        #region Attach / Detach

        public void Detach(ChildWindowDecorator decorator)
        {
            if (decorator.IsModal)
                return;

            //---- Must be attached
            if (decorator.DetachableWindow != null)
                return;

            //---- Unselect
            if (decorator == _selectedChildWindow)
                _selectedChildWindow = null;

            //---- Remove from canvas
            FrameworkElement parent = decorator.Parent as FrameworkElement;
            ChildWindowsCanvas.Children.Remove(parent);

            //---- Create the window
            ChildDetachableWindow window = new ChildDetachableWindow();
            window.Child = decorator;

            window.UpdateLayout();
            window.Show();
        }

        public void Attach(ChildWindowDecorator decorator)
        {
            if (decorator.IsModal)
                return;

            //---- Must be detached
            if (decorator.DetachableWindow == null)
                return;

            //---- Free the window
            decorator.DetachableWindow.Child = null;

            //---- Add to the canvas
            FrameworkElement parent = decorator.Parent as FrameworkElement;
            ChildWindowsCanvas.Children.Add(parent);
        }

        #endregion

        #region AlignIconsToGrid

        int offsetX = 0;
        int offsetY = 0;
        int gridWidth = 100;
        int gridHeight = 50;

        public void AlignIconsToGrid()
        {
            InsureVisibleDesktopIcons();

            List<DesktopIcon> exclude = new List<DesktopIcon>();
            for (int index = 0; index < ChildWindowsCanvas.Children.Count; index++)
                if (ChildWindowsCanvas.Children[index] is DesktopIcon)
                {
                    //---- Align
                    DesktopIcon icon = ChildWindowsCanvas.Children[index] as DesktopIcon;

                    double iconLeft = Canvas.GetLeft(icon) - offsetX + icon.ActualWidth / 2;
                    double iconTop = Canvas.GetTop(icon) - offsetY + icon.ActualHeight / 2;

                    // Keep it to the limit of the visual zone (desktop)
                    if (Canvas.GetTop(icon) < 0)
                        iconTop = gridHeight + Canvas.GetTop(icon) - offsetY + icon.ActualHeight / 2;

                    // Fuzzy logic
                    iconLeft += gridWidth / 2;
                    iconTop += gridHeight / 2;

                    double left = gridWidth * (int)(iconLeft / gridWidth);
                    double top = gridHeight * (int)(iconTop / gridHeight);

                    List<DesktopIcon> over = IsOverIcon(left, top, index);
                    while (over.Count > 0)
                    {
                        top += gridHeight;
                        if (top > (ChildWindowsCanvas.ActualHeight - gridHeight))
                        {
                            top = 0;
                            left += gridWidth;
                        }

                        over = IsOverIcon(left, top, index);
                    }

                    // Re-center the icon
                    left -= icon.ActualWidth / 2;
                    top -= icon.ActualHeight / 2;

                    MoveDesktopIcon(icon, new Point(offsetX + left, offsetY + top));
                }
        }

        private List<DesktopIcon> IsOverIcon(double left, double top, int iconIndex)
        {
            List<DesktopIcon> list = new List<DesktopIcon>(0);

            for (int index = 0; index < Math.Min(iconIndex, ChildWindowsCanvas.Children.Count); index++)
                if (ChildWindowsCanvas.Children[index] is DesktopIcon)
                {
                    DesktopIcon icon = ChildWindowsCanvas.Children[index] as DesktopIcon;
                    double iconLeft = Canvas.GetLeft(icon) - offsetX + icon.ActualWidth / 2;
                    double iconTop = Canvas.GetTop(icon) - offsetY + icon.ActualHeight / 2;

                    if (left == iconLeft && top == iconTop)
                        list.Add(icon);
                }

            return list;
        }


        #endregion

        #region ReorganizeIconsToGrid

        public void OrganizeIconsToGrid()
        {
            InsureVisibleDesktopIcons();

            double left = offsetX;
            double top = offsetY;
            for (int index = 0; index < ChildWindowsCanvas.Children.Count; index++)
                if (ChildWindowsCanvas.Children[index] is DesktopIcon)
                {
                    //---- Align
                    DesktopIcon icon = ChildWindowsCanvas.Children[index] as DesktopIcon;

                    MoveDesktopIcon(icon, new Point(left + gridWidth / 2 + (gridWidth - icon.ActualWidth) / 2, top + gridHeight / 2 + (gridHeight - icon.ActualHeight) / 2));

                    top = top + gridHeight;
                    if (top > (ChildWindowsCanvas.ActualHeight - gridHeight))
                    {
                        top = offsetY;
                        left += gridWidth;
                    }
                }
        }

        #endregion

        #region BringToTop

        internal void BringToTop(UserControl window)
        {
            if (window is DesktopIcon)
                BringToTopDesktopIcon((DesktopIcon)window);
            else
                BringToTopChildWindow(window);
        }

        private void BringToTopChildWindow(UserControl window)
        {
            ChildWindowsCanvas.Children.Remove(window);
            ChildWindowsCanvas.Children.Add(window);
        }

        private void BringToTopDesktopIcon(DesktopIcon icon)
        {
            ChildWindowsCanvas.Children.Remove(icon);
            ChildWindowsCanvas.Children.Remove(icon.RepresentingControl);

            // Index '0' is the content presenter
            for (int index = 1; index < ChildWindowsCanvas.Children.Count; index++)
            {
                DesktopIcon element = ChildWindowsCanvas.Children[index] as DesktopIcon;
                if (element == null)
                {
                    ChildWindowsCanvas.Children.Insert(index, icon);

                    // Bring the "representing control" to the top
                    ChildWindowsCanvas.Children.Add(icon.RepresentingControl);
                    return;
                }
            }
        }

        #endregion

        #region Selection : Clear

        public void ClearSelection()
        {
            lock (_selectedDesktopIcons)
                for (int index = _selectedDesktopIcons.Count - 1; index > -1; index--)
                {
                    DesktopIcon icon = (DesktopIcon)_selectedDesktopIcons[index];
                    icon.IsSelected = false;
                }

            _selectedChildWindow = null;
        }

        #endregion

        #region Xml

        public XmlNodeList FindXml()
        {
            return ChildWindowDecorator.FindXml(_key);
        }

        #endregion

        #region Helpers

        public bool IsMouseOverDekstopElement(Point mousePosition)
        {
            foreach (UIElement uiElement in ChildWindowsCanvas.Children)
                if (uiElement is UserControl)
                {
                    UserControl child = (UserControl)uiElement;

                    if (mousePosition.X >= Canvas.GetLeft(child) &&
                        mousePosition.X <= (Canvas.GetLeft(child) + child.ActualWidth) &&
                        mousePosition.Y >= Canvas.GetTop(child) &&
                        mousePosition.Y <= (Canvas.GetTop(child) + child.ActualHeight))
                        return true;
                }

            return false;
        }

        public bool IsMouseOverChildWindow(Point mousePosition)
        {
            foreach (UIElement uiElement in ChildWindowsCanvas.Children)
                if (uiElement is UserControl)
                {
                    UserControl child = (UserControl)uiElement;

                    if (child is DesktopIcon)
                        continue;

                    if (mousePosition.X >= Canvas.GetLeft(child) &&
                        mousePosition.X <= (Canvas.GetLeft(child) + child.ActualWidth) &&
                        mousePosition.Y >= Canvas.GetTop(child) &&
                        mousePosition.Y <= (Canvas.GetTop(child) + child.ActualHeight))
                        return true;
                }

            return false;
        }

        public bool IsMouseOverSelectedDesktopIcon(Point mousePosition)
        {
            foreach (UIElement uiElement in ChildWindowsCanvas.Children)
                if (uiElement is DesktopIcon)
                {
                    DesktopIcon child = (DesktopIcon)uiElement;

                    if (!child.IsSelected)
                        continue;

                    if (mousePosition.X >= Canvas.GetLeft(child) &&
                        mousePosition.X <= (Canvas.GetLeft(child) + child.ActualWidth) &&
                        mousePosition.Y >= Canvas.GetTop(child) &&
                        mousePosition.Y <= (Canvas.GetTop(child) + child.ActualHeight))
                        return true;
                }

            return false;
        }

        //public void SetTopInnerWindow(Type type)
        //{
        //    foreach (UIElement ui in innerCanvas.Children)
        //        if (ui.GetType().Equals(type))
        //        {
        //            SetTopInnerWindow(ui as UserControl);
        //            return;
        //        }
        //}

        //public UserControl RemoveInnerWindow(Type type)
        //{
        //    foreach (UIElement ui in innerCanvas.Children)
        //        if (ui.GetType().Equals(type))
        //        {
        //            innerCanvas.Children.Remove(ui);
        //            return ui as UserControl;
        //        }
        //    return null;
        //}

        //public bool SearchInnerWindowType(Type type)
        //{
        //    foreach (UIElement ui in innerCanvas.Children)
        //        if (ui.GetType().Equals(type))
        //            return true;

        //    return false;
        //}

        //public UIElement GetInnerWindowType(Type type)
        //{
        //    foreach (UIElement ui in innerCanvas.Children)
        //        if (ui.GetType().Equals(type))
        //            return ui;

        //    return null;
        //}

        //public void CloseInnerWindowType(Type type)
        //{
        //    foreach (UIElement ui in innerCanvas.Children)
        //        if (ui.GetType().Equals(type))
        //        {
        //            RemoveInnerWindow(ui as UserControl);
        //            return;
        //        }
        //}

        #endregion

        #region InsureVisibleDesktopIcons

        private void InsureVisibleDesktopIcons()
        {
            for (int index = 0; index < ChildWindowsCanvas.Children.Count; index++)
                if (ChildWindowsCanvas.Children[index] is DesktopIcon)
                    InsureVisible(((DesktopIcon)ChildWindowsCanvas.Children[index]).Decorator);
        }

        #endregion

        #region InsureVisible

        internal void InsureVisible(ChildWindowDecorator decorator)
        {
            //---- Window
            UserControl control = (UserControl)decorator.Parent;

            if (Canvas.GetLeft(control) >= ChildWindowsCanvas.ActualWidth)
                Canvas.SetLeft(control, ChildWindowsCanvas.ActualWidth - 10 - control.ActualWidth);

            if (Canvas.GetTop(control) >= ChildWindowsCanvas.ActualHeight)
                Canvas.SetTop(control, ChildWindowsCanvas.ActualHeight - 10 - control.ActualHeight);

            if (Canvas.GetBottom(control) <= 0)
                Canvas.SetTop(control, 10);

            if (Canvas.GetRight(control) <= 0)
                Canvas.SetLeft(control, 10);

            //---- Icon
            if (Canvas.GetLeft(decorator.DesktopIcon) == Int32.MinValue &&
                Canvas.GetTop(decorator.DesktopIcon) == Int32.MinValue)
                return;

            if (Canvas.GetLeft(decorator.DesktopIcon) >= ChildWindowsCanvas.ActualWidth)
                Canvas.SetLeft(decorator.DesktopIcon, ChildWindowsCanvas.ActualWidth - 10 - decorator.DesktopIcon.ActualWidth);

            if (Canvas.GetTop(decorator.DesktopIcon) >= ChildWindowsCanvas.ActualHeight)
                Canvas.SetTop(decorator.DesktopIcon, ChildWindowsCanvas.ActualHeight - 10 - decorator.DesktopIcon.ActualHeight);

            if (Canvas.GetBottom(decorator.DesktopIcon) <= 0)
                Canvas.SetTop(decorator.DesktopIcon, 10);

            if (Canvas.GetRight(decorator.DesktopIcon) <= 0)
                Canvas.SetLeft(decorator.DesktopIcon, 10);
        }

        #endregion

    }
}
